import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:client/common/fun.dart';
import 'package:client/provider/app_provider.dart';
import 'package:client/common/config.dart';
import 'package:client/common/event.dart';
import 'package:client/common/info_route.dart';
import 'package:provider/provider.dart';

class ConnMsg {
  int cmd;
  String info;

  ConnMsg(this.cmd, this.info);

  @override
  String toString() {
    return '(cmd: $cmd, info: $info)';
  }
}

class ByteMsg {
  static List<int> msg2Byte(ConnMsg msg) {
    BytesBuilder builder = BytesBuilder();

    var infoByte = utf8.encode(msg.info);
    var len = infoByte.length + 4;
    //byteLen
    ByteData b1 = ByteData(2);
    b1.setUint16(0, len, Endian.big);
    builder.add(b1.buffer.asUint8List());
    //cmd
    ByteData b2 = ByteData(2);
    b2.setUint16(0, msg.cmd, Endian.big);
    builder.add(b2.buffer.asUint8List());
    //info
    builder.add(infoByte);
    return builder.takeBytes();
  }

  static ConnMsg? byte2Msg(List<int> data) {
    try {
      print("data-->");
      print(data);

      ByteData bCmd = ByteData.sublistView(Uint8List.fromList(data), 2, 4);
      int cmd = bCmd.getUint16(0, Endian.big);
      print("cmd-->");
      print(cmd);

      if (data.length <= 4) {
        return ConnMsg(cmd, "");
      }
      try {
        var info = utf8.decode(data.sublist(4).toList(), allowMalformed: true);
        print("info-->");
        print(info);
        return ConnMsg(cmd, info);
      } catch (e) {
        print("Error decoding info:");
        print(e);
        return null;
      }
    } catch (e) {
      print(e);
    }
    return null;
  }
}

class Conn {
  static Future<Socket>? _conn;
  static List<int> buffer = [];

  static start() {
    print("tcp1");
    print(_conn);
    if (_conn == null) {
      print("tcp2");

      try {
        Config config = AppProvider.getConfig();

        _conn = Socket.connect(config.tcpHost, config.tcpPort);

        onValue(Socket conn) {
          conn.listen((List<int> data) {
            print("conn data in-->");
            //将接收到的数据添加到缓冲区
            buffer.addAll(data);
            print("buffer-->");
            print(buffer);
            print(buffer.length);
            while (buffer.length >= 4) {
              //解析数据
              ByteData bLen =
                  ByteData.sublistView(Uint8List.fromList(buffer), 0, 2);
              int len = bLen.getUint16(0, Endian.big);
              print("len-->");
              print(len);
              if (buffer.length < len) {
                //数据不完整，等待更多数据
                print("数据不完整，等待更多数据");
                print("buffer.length < len + 2");
                print("buffer.length: ${buffer.length}, len + 2: ${len + 2}");
                print("buffer: $buffer");
                return;
              }
              List<int> subData;
              try {
                subData = buffer.sublist(0, len);
              } catch (e) {
                print(e);
                print(buffer);
                buffer = [];
                Fun.dialog("错误", "数据解析失败，可能是数据不完整或格式错误");
                return;
              }

              print("subData-->");
              print(subData);

              var connMsg = ByteMsg.byte2Msg(subData);
              print(connMsg);
              if (connMsg == null) {
                Fun.dialog("错误", "数据解析失败");
                return;
              }
              InfoRoute.action(connMsg.cmd, connMsg.info);

              //从数据中移除已解析的部分
              buffer.removeRange(0, len);
              print("buffer after sublist-->");
              print(buffer);
            }
          }, onDone: () {
            //断开连接
            print("done");
            bus.emit(EventBusSet.tcpLinkedBreak);
          }, onError: (err) {
            print(err);
          });

          bus.emit(EventBusSet.tcpLinked);
        }

        _conn?.then(onValue).catchError((error) {
          _conn = null;
          print('Error:$error');
          Fun.dialog("错误1", error.toString());
        });
      } catch (e) {
        Fun.dialog("错误2", e.toString());
      }
    }
  }

  static send(int cmd, String info) {
    if (_conn == null) {
      Fun.dialog("错误", "请先连接服务器");
      return false;
    }

    _conn!.then((Socket conn) {
      conn.add(ByteMsg.msg2Byte(ConnMsg(cmd, info)));
    });
  }

  static close() {
    if (_conn != null) {
      _conn!.then((Socket conn) {
        _conn = null;
        conn.destroy();
        print("tcp close");
      });
    }
  }
}
